package io.milton.mini;

import java.util.Date;
import io.milton.vfs.db.Credential;
import io.milton.vfs.db.PasswordCredential;
import io.milton.vfs.db.Profile;
import io.milton.http.http11.auth.DigestGenerator; 
import io.milton.http.http11.auth.DigestResponse;
import io.milton.vfs.db.utils.SessionManager;
import java.util.ArrayList;

/**
 *
 * @author brad
 */
public class PasswordManager {

    private static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(PasswordManager.class);
    private final DigestGenerator digestGenerator;
    private String realm = "milton-mini";

    public PasswordManager(DigestGenerator digestGenerator) {
        this.digestGenerator = digestGenerator;
    }

    public PasswordManager() {
        this.digestGenerator = new DigestGenerator();
    }

    public void setPassword(Profile user, String newPassword) {
        // Attempt to locate a PasswordCredential
        PasswordCredential epc = null;
        if (user.getCredentials() != null) {
            for (Credential c : user.getCredentials()) {
                if (c instanceof PasswordCredential) {
                    epc = (PasswordCredential) c;
                    break;
                }
            }
        }
        if (epc == null) {
            epc = new PasswordCredential();
            epc.setCreatedDate(new Date());
            epc.setModifiedDate(new Date());
            epc.setProfile(user);
            
            if( user.getCredentials() == null ) {
                user.setCredentials(new ArrayList<Credential>());
            }
            user.getCredentials().add(epc);
        }
        String hash = calcPasswordHash(user.getName(), newPassword);
        epc.setPassword(hash);
        SessionManager.session().save(user);
        SessionManager.session().save(epc);
        
    }

    public String calcPasswordHash(String userName, String password) {
        String a1md5 = digestGenerator.encodePasswordInA1Format(userName, realm, password);
        return a1md5;
    }

    public String getRealm() {
        return realm;
    }

    public void setRealm(String realm) {
        this.realm = realm;
    }

    public boolean verifyDigest(DigestResponse digest, Profile user) {
        PasswordCredential epc = null;
        if (user.getCredentials() != null) {
            for (Credential c : user.getCredentials()) {
                if (c instanceof PasswordCredential) {
                    epc = (PasswordCredential) c;
                    break;
                }
            }
        }
        if (epc == null) {
            log.warn("Profile is not associated with a password: profileId=" + user.getId());
            return false;
        }
        //String actualPassword = epc.getPassword();
        String a1Md5 = epc.getPassword();
        //String a1Md5 = digestGenerator.encodePasswordInA1Format(user.getName(), realm, actualPassword);
        String expectedResp = digestGenerator.generateDigestWithEncryptedPassword(digest, a1Md5);
        String actualResp = digest.getResponseDigest();
        if (expectedResp.equals(actualResp)) {
//            log.info("verifyDigest: ok");
            return true;
        } else {
            System.out.println("digests don't match!!!!");
            System.out.println("expected (ie generated by server): " + expectedResp);
            System.out.println("actual (ie given in request): " + actualResp);
            System.out.println("cnonce: " + digest.getCnonce());
            System.out.println("method: " + digest.getMethod());
            System.out.println("nc: " + digest.getNc());
            System.out.println("nonce:" + digest.getNonce());
            System.out.println("qop: " + digest.getQop());
            System.out.println("realm: " + digest.getRealm());
            System.out.println("uri: " + digest.getUri());                    
            System.out.println("user: " + digest.getUser());
            System.out.println("password a1md5: " + a1Md5);
            return false;
        }
    }

    public boolean verifyPassword(Profile user, String requestPassword) {
        if (requestPassword != null) {
            log.trace("verify password: " + user.getName());
            if (user.getCredentials() != null && !user.getCredentials().isEmpty()) {
                for (Credential c : user.getCredentials()) {
                    if (c instanceof PasswordCredential) {
                        PasswordCredential pc = (PasswordCredential) c;
                        if (matches(user.getName(), pc, requestPassword)) {
                            log.trace("Password check ok");
                            return true;
                        } else {
                            log.warn("Non-matching password");
                        }
                    }
                }
            } else {
                log.warn("null or empty creds for: " + user.getId());
            }
        }
        log.warn("Basic login failed for user: " + user.getEmail());
        return false;
    }
    

    private boolean matches(String username, PasswordCredential pc, String requestPassword) {
        String a1Md5 = pc.getPassword();
        String reqHash = calcPasswordHash(username, requestPassword);
        if(a1Md5.equals(reqHash)) {
            return true;
        } else {
            log.warn("password hashes do not match: " + a1Md5 + " != " + reqHash);
            return false;
        }
    }
}
